package com.hyf.processor.core;

import com.google.auto.service.AutoService;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.HashSet;
import java.util.Set;

/**
 * 还可以通过-processor参数来执行编译时需要附带的注解处理器，多个逗号分隔。
 * 还可以使用 -XprintRounds 和 -XprintProcessorInfo 参数来查看注解处理器运作的详细信息。
 *
 * @author baB_hyf
 * @date 2020/11/23
 */
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.hyf.processor.core.GetterSetter")
public class GetterSetterProcessor extends AbstractProcessor {

    private Messager messager; // 消息

    private JavacTrees javacTrees; // 抽象语法树工具

    private TreeMaker treeMaker; // 操作节点工具 - 核心工具

    private Names names; // 处理名称工具

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latest(); // 指定可处理的java版本
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {

        super.init(processingEnv); // 注解处理器框架提供的上下文环境

        // 额外初始化一些资源操作对象

        this.messager = processingEnv.getMessager();
        this.javacTrees = JavacTrees.instance(processingEnv);

        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);

    }

    /**
     * 核心处理逻辑
     *
     * @param annotations 感兴趣的注解
     * @param roundEnv    当前轮次（Round）的抽象语法树节点，所有节点类型（ElementKind）
     * @return 是否改动过节点
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        // 当前处理器已处理过，不在进行处理
        if (roundEnv.processingOver()) {
            return true;
        }

        print("开始处理");
        print("处理注解：" + annotations);
        messager.printMessage(Diagnostic.Kind.NOTE, "roundEnv ->" + roundEnv);

        for (TypeElement annotation : annotations) {

            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation);

            for (Element element : elements) {
                print("处理注解：" + annotation + "开始处理元素：" + element);

                // 存放所有变量，也可以list，不过这里不太方便
                Set<JCTree.JCVariableDecl> paramSet = new HashSet<>();

                // 获取元素对象的抽象语法树
                JCTree jcTree = javacTrees.getTree(element);

                // 标准的访问者模式
                jcTree.accept(new TreeTranslator() {

                    /**
                     * 遍历每个变量
                     */
                    @Override
                    public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
                        paramSet.add(jcVariableDecl); // 存起来
                        super.visitVarDef(jcVariableDecl);
                    }

                    @Override
                    public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {

                        super.visitClassDef(jcClassDecl); // 会先走 visitVarDef

                        // 转换
                        List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
                        for (JCTree.JCVariableDecl jcVariableDecl : paramSet) {
                            jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
                        }

                        print("------------------------\n本次处理参数：");
                        jcVariableDeclList.forEach((var) -> print(var));
                        print("------------------------");

                        // 获取所有getter/setter方法
                        List<JCTree.JCMethodDecl> jcMethodDeclList = generateMethod(jcVariableDeclList);

                        // 添加到类中
                        for (JCTree.JCMethodDecl jcMethodDecl : jcMethodDeclList) {
                            jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);
                        }


                    }
                });


            }
        }

        print("处理结束");

        // 指示处理器改变过代码，需要修改语法树的内容
        // 编译器会重新回到解析及填充符号表的过程
        return true;
    }

    private List<JCTree.JCMethodDecl> generateMethod(List<JCTree.JCVariableDecl> jcVariableDeclList) {

        List<JCTree.JCMethodDecl> jcMethodDeclList = List.nil();

        for (JCTree.JCVariableDecl jcVariableDecl : jcVariableDeclList) {

            JCTree.JCMethodDecl getter = getGetter(jcVariableDecl);
            JCTree.JCMethodDecl setter = getSetter(jcVariableDecl);

            jcMethodDeclList = jcMethodDeclList.append(getter);
            jcMethodDeclList = jcMethodDeclList.append(setter);
        }

        return jcMethodDeclList;
    }

    private JCTree.JCMethodDecl getGetter(JCTree.JCVariableDecl jcVariableDecl) {
        JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC); //访问修饰符

        Name methodName = names.fromString("get" + upper(jcVariableDecl.name.toString())); // 方法名

        List<JCTree.JCStatement> jcReturns = List.of(treeMaker.Return(
                treeMaker.Select(
                        // this -> name
                        treeMaker.Ident(names.fromString("this")), jcVariableDecl.name)
                )
        ); // 代码块
        JCTree.JCBlock block = treeMaker.Block(0, jcReturns); // 0 -> 没有任何修饰符

        return treeMaker.MethodDef(
                modifiers, // 访问修饰符
                methodName, // 方法名
                jcVariableDecl.vartype, // 返回类型
                List.nil(), // 泛型列表
                List.nil(), // 参数列表
                List.nil(), // 异常列表
                block, // 方法体
                null // 默认值，注解才有
        );
    }

    private JCTree.JCMethodDecl getSetter(JCTree.JCVariableDecl jcVariableDecl) {
        JCTree.JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC); //访问修饰符

        JCTree.JCPrimitiveTypeTree rtnType = treeMaker.TypeIdent(TypeTag.VOID); // 方法返回类型

        Name methodName = names.fromString("set" + upper(jcVariableDecl.name.toString())); // 方法名

        JCTree.JCVariableDecl param = treeMaker.VarDef(
                treeMaker.Modifiers(Flags.PARAMETER), // 变量类型 - 参数
                jcVariableDecl.getName(), // 参数名
                jcVariableDecl.vartype, // 参数类型
                null // ...
        ); // 形参

        param.pos = jcVariableDecl.pos; // 坑，1小时

        List<JCTree.JCStatement> jcAssigns = List.of(treeMaker.Exec(
                // =
                treeMaker.Assign(
                        // this.xxx, xxx
                        treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString(jcVariableDecl.name.toString())), treeMaker.Ident(param.name)
                )
        ));// 代码块

        JCTree.JCBlock block = treeMaker.Block(0, jcAssigns); // 0 -> 没有任何修饰符

        return treeMaker.MethodDef(
                modifiers, // 访问修饰符
                methodName, // 方法名
                rtnType, // 返回类型
                List.nil(), // 泛型列表
                List.of(param), // 参数列表
                List.nil(), // 异常列表
                block, // 方法体
                null // 默认值，注解才有
        );
    }

    private String upper(String str) {
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    private void print(Object msg) {
        System.out.println(msg.toString());
    }
}
